﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Data.SqlClient;

namespace NMigrate
{
	public class SqlFileHandler : FileHandler, IHasOutput
	{
		public SqlFileHandler()
		{
			HasOutput.ConfigDefault(this);
			SqlCmdPath = @"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE";
		}
		#region FileHandler Members

		public override string Extension
		{
			get
			{
				return "sql";
			}
		}

		/// <summary>
		/// Used Connection string if SelectConnectionString is null or return null
		/// </summary>
		public string DefaultConnectionString
		{
			get;
			set;
		}

		/// <summary>
		/// Select connection string depending on the handled file, return null to use the DefaultConnectionString.
		/// </summary>
		public Func<FileInfo, string> SelectConnectionString
		{
			get;
			set;
		}

		/// <summary>
		/// PAth to SQLCMD.exe executable
		/// </summary>
		public string SqlCmdPath
		{
			get;
			set;
		}


		private string GetConnectionString(FileInfo file)
		{
			if(SelectConnectionString == null)
			{
				if(DefaultConnectionString == null)
				{
					throw new InvalidOperationException("SelectConnectionString or DefaultConnectionString should be set for this " + this.GetType().Name);
				}
				return DefaultConnectionString;
			}
			var connectionString = SelectConnectionString(file);
			if(connectionString == null)
			{
				if(DefaultConnectionString == null)
				{
					throw new InvalidOperationException("SelectConnectionString returned null, DefaultConnectionString should be set for this " + this.GetType().Name);
				}
				return DefaultConnectionString;
			}
			return connectionString;
		}

		private void AssertSettingsAreSet()
		{
			if(String.IsNullOrEmpty(SqlCmdPath))
			{
				throw new InvalidOperationException("SqlCmdPath should not be empty, and should target SQLCMD.exe program");
			}
			if(!File.Exists(SqlCmdPath))
			{
				throw new InvalidOperationException("SqlCmdPath does not exist (" + SqlCmdPath + "), please change it to target SQLCMD.exe program");
			}
			if(String.IsNullOrEmpty(DefaultConnectionString) && SelectConnectionString == null)
			{
				throw new InvalidOperationException("The DefaultConnectionString property should not be empty if SelectConnectionString delegate is null");
			}
		}



		public override void Execute(System.IO.FileInfo file, Configuration args)
		{
			AssertSettingsAreSet();
			var process = new Process();
			process.StartInfo.FileName = SqlCmdPath;
			StringBuilder arguments = new StringBuilder();

			
			var connStr = new SqlConnectionStringBuilder(GetConnectionString(file));
			arguments.Append("-S " + connStr.DataSource + " ");
			if(connStr.IntegratedSecurity)
			{
				arguments.Append("-E ");
			}
			else
			{
				arguments.Append("-U " + connStr.UserID + " ");
				arguments.Append("-P " + connStr.Password + " ");
			}
			arguments.Append("-i \"" + file.FullName + "\" ");
			process.StartInfo.Arguments = arguments.ToString();
			process.StartInfo.UseShellExecute = false;
			process.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);
			process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
			process.Start();
			process.WaitForExit();
		}

	

		public TextWriter Out
		{
			get;
			set;
		}
		public TextWriter Error
		{
			get;
			set;
		}


		void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
		{
			if(Error != null)
				Error.WriteLine(e.Data);
		}
		void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
		{
			if(Out != null)
				Out.WriteLine(e.Data);
		}


		public override bool IsTemplated(FileInfo file)
		{
			return true;
		}

		#endregion
	}
}
